package net.tngou.db.lucene;



import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import java.util.Map.Entry;
import java.util.Set;

import net.tngou.db.entity.Field;
import net.tngou.db.entity.Page;

import org.apache.commons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wltea.analyzer.lucene.IKAnalyzer;




/**
 * 
* @ClassName: LuceneManage
* @Description: TODO Lucene 操作管理
* @author tngou@tngou.net (www.tngou.net)
* @date 2015年5月20日 下午2:56:11
*
 */
public class LuceneManage {

	
	private static Logger log = LoggerFactory.getLogger(LuceneManage.class);
	private static LuceneManage  luceneManage= null;
	private static Config CONFIG=null;
	private Analyzer analyzer=null;
	IndexWriterConfig config  = null;
	private static  String DEFAULT_TABLE = "";
	/**
	 * 单例方法
	 * @return
	 */
	public final static LuceneManage getInstance (){
		if(luceneManage==null)
		{
		   return new LuceneManage();
		}else
		{
			return luceneManage;
		}
	}
	
	private LuceneManage()
	{
		CONFIG=Config.getInstance();
		DEFAULT_TABLE=CONFIG.getTable();
		analyzer = new IKAnalyzer();
		config = new IndexWriterConfig(Version.LUCENE_4_10_2, analyzer);
	}
	
	
	/**
	 *  创建表
	* @Title: createTable
	* @Description: TODO(这里用一句话描述这个方法的作用)
	* @param @param DBName
	* @param @param re    设定文件
	* @return void    返回类型
	* @throws
	 */
	public boolean  createTable(String tableName) {
		
		boolean r=true;
		File path= new File(CONFIG.getPath());
		if(!path.isDirectory())
		{
			path.mkdirs();
		}
		if(!path.canRead())
		{
			path.setExecutable(true);//设置可执行权限  
			path.setReadable(true);//设置可读权限  
			path.setWritable(true);//设置可写权限 
		}
		
						
		File docDir= new File(CONFIG.getPath(), tableName);
		if(docDir.isDirectory())
		{
			
			r=false;
		}
		else
		{
			docDir.mkdirs();
			
		}
		
		if(!docDir.canRead())
		{
			docDir.setExecutable(true);//设置可执行权限  
			docDir.setReadable(true);//设置可读权限  
			docDir.setWritable(true);//设置可写权限 
		}
		
		
		return r;
	}
	
	/**
	 * 
	* @Title: renameTable
	* @Description: 表重新命名
	* @param @param old_tableName
	* @param @param new_tableName
	* @param @return    设定文件
	* @return boolean    返回类型
	* @throws
	 */
	public boolean renameTable(String old_tableName,String new_tableName) {
		boolean r=true;
		File oldDir= new File(CONFIG.getPath(), old_tableName);
		if(!oldDir.isDirectory())
		{
			return false;
		}
		File newDir= new File(CONFIG.getPath(), new_tableName);
		if(newDir.isDirectory())
		{
			return false;
		}
		oldDir.renameTo(newDir);
		return r;
		
	}
	
	/**
	 * 
	* @Title: dropTable
	* @Description: 删除表
	* @param @param tableNames    设定文件
	* @return void    返回类型
	* @throws
	 */
	public boolean dropTable(String tableName) {
		
		boolean r=true;		
		File docDir= new File(CONFIG.getPath(), tableName);
		if(docDir.isDirectory())
		{			
				try {
					FileUtils.deleteDirectory(docDir);
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}			
		}else
		{
			r=false;
		}
		
		return r;
		
		
	
		
	}
	
	
	/**
	 * 
	* @Title: clearTable
	* @Description: 清除数据
	* @param @param tableNames    设定文件
	* @return void    返回类型
	* @throws
	 */
	public void clearTable(String tableName) {
	
		dropTable(tableName);
		createTable( tableName);
	}
	
	
	/**
	 * 
	* @Title: delete
	* @Description: 按照主键删除数据
	* @param @param tableName
	* @param @param id    设定文件
	* @return void    返回类型
	* @throws
	 */
	public void delete(Field field,String tableName) {
		
		File indexPath= new File(CONFIG.getPath(), tableName);
		try {
			Directory directory = FSDirectory.open(indexPath);
			IndexWriter iwriter = new IndexWriter(directory, config);
			iwriter.deleteDocuments(new Term(field.getName(), field.getValue())); //删除主键
		
			iwriter.commit();
			iwriter.close();
//			directory.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		

	}
	
	/**
	 * 
	* @Title: add
	* @Description: 添加数据
	* @param @param map    设定文件
	* @return void    返回类型
	* @throws
	 */
	public void add( List<Field> list,String tableName) {
		
	
		File indexPath= new File(CONFIG.getPath(), tableName);		 
		try {
			Directory directory = FSDirectory.open(indexPath);
			IndexWriter iwriter = new IndexWriter(directory, config);
			Document doc = new Document();
			
			for (Field field : list) {
										
				if(field.getType().equals(Field.Type.Key))
				{
					
					iwriter.deleteDocuments(new Term(field.getName(), field.getValue())); //删除主键
					doc.add(new StringField(field.getName(), field.getValue(),Store.YES)); //不用分词 
					
				}else if(field.getType().equals(Field.Type.String))
				{
					doc.add(new StringField(field.getName(), field.getValue(),Store.YES)); //不用分词 
				}else if(field.getType().equals(Field.Type.Text))
				{
					doc.add(new TextField(field.getName(), field.getValue(), Store.YES)); //对String进行分词存储
				}
				
				
			}
			
			iwriter.addDocument(doc);
			iwriter.commit();
			iwriter.close();
			directory.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	
	
	 /**
	  * 
	 * @Title: update
	 * @Description: 更新数据
	 * @param @param tableName
	 * @param @param term
	 * @param @param updates    设定文件
	 * @return void    返回类型
	 * @throws
	  */
	public void update( String tableName,Field term,Field ...updates) {
		
		
		File indexPath= new File(CONFIG.getPath(), tableName);
		
		 
		try {
			Directory directory = FSDirectory.open(indexPath);
			IndexWriter iwriter = new IndexWriter(directory, config);
			 IndexSearcher isearcher = _getSearcher(tableName);
 			 
			 Query query= new TermQuery(new Term(term.getName(), term.getValue()));
			 TopDocs topDocs = isearcher.search(query, 1);
		
			 ScoreDoc[] list = topDocs.scoreDocs;
			 if(list.length>0)
			 {
				 Document doc = isearcher.doc(list[0].doc);
				
				 for (Field field : updates) {
					
						if(field.getType().equals(Field.Type.Key))
						{
							
							doc.add(new StringField(field.getName(), field.getValue(),Store.YES)); //不用分词 
						}else if(field.getType().equals(Field.Type.String))
						{
							doc.add(new StringField(field.getName(), field.getValue(),Store.YES)); //不用分词 
						}else if(field.getType().equals(Field.Type.Text))
						{
							doc.add(new TextField(field.getName(), field.getValue(), Store.YES)); //对String进行分词存储
						}
				
				}
				 
				 iwriter.updateDocument(new Term(term.getName(), term.getValue()), doc);
				 
				 
			 }
		
				
			
			
			iwriter.commit();
			iwriter.close();
			directory.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	
	
	/**
	 * 
	* @Title: get
	* @Description: 驱动数据
	* @param @param tableName
	* @param @param id
	* @param @return    设定文件
	* @return Map<String,Object>    返回类型
	* @throws
	 */
	public Map<String, Object> get(Field field,String ... tableNames)  {
		Map<String, Object> map = new HashMap<String, Object>();
		
		try {
			 
			 IndexSearcher isearcher = _getSearcher(tableNames);
			 			 
			 Query query= new TermQuery(new Term(field.getName(), field.getValue()));
			 TopDocs topDocs = isearcher.search(query, 1);
		
			 ScoreDoc[] list = topDocs.scoreDocs;
		
			 if(list.length>0)
			 {
				 Document doc = isearcher.doc(list[0].doc);
				 List<IndexableField> fields = doc.getFields();
				 fields.forEach(e->{
					 IndexableField indexfield=e;
					 map.put(indexfield.name(),  indexfield.stringValue());
					 
				 });
			 }

			 
		 } catch (IOException    e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
		
		return map;
	}
	
	
	

	
	/**
	 * 
	* @Title: get
	* @Description: 取得数据
	* @param @param tableName
	* @param @param start
	* @param @param size
	* @param @param field
	* @param @param sortField
	* @param @return    设定文件
	* @return Page    返回类型
	* @throws
	 */
	public Page get(int start,int size,Field field,SortField[] sortField,String ... tableNames) {
		
	
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		int total=0;
	
		
		try {
			 
			
			 IndexSearcher isearcher = _getSearcher(tableNames);
			 Query query= new TermQuery(new Term(field.getName(),field.getValue()));
			 TopDocs topDocs=null;
				if(sortField==null)  //排序字段为空 ，也就Top排序
				{
					topDocs=isearcher.search(query, CONFIG.getSize());
				}else
				{
					topDocs=isearcher.search(query, CONFIG.getSize(), new Sort(sortField));
				}
			 ScoreDoc[] docs = topDocs.scoreDocs;
		   total =docs.length;
			 
			for (int i = start; i < docs.length&&i<(start+size); i++) {
				 
				Map<String, Object> map = new HashMap<String, Object>();
				Document doc = isearcher.doc(docs[i].doc);
				 List<IndexableField> fields = doc.getFields();
				 fields.forEach(e->{
					 IndexableField indexablefield=e;
					 map.put(indexablefield.name(),  indexablefield.stringValue());
					
					 
				 });
				
				 list.add(map);
			 }
			 		 
			 
//			 ireader.close(); 
		 } catch (IOException    e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
		
		return new Page(start, size ,total, list);
		
	}
	
	
	/**
	 * 
	* @Title: get
	* @Description: 取得数据
	* @param @param tableName
	* @param @param start
	* @param @param size
	* @param @param reverse
	* @param @return    设定文件
	* @return Page    返回类型
	* @throws
	 */
	public Page get(int start,int size, boolean reverse,String  tableName) {
		
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		int total=0;

		File indexPath= new File(CONFIG.getPath(), tableName);
		
		 try {
			 Directory directory = FSDirectory.open(indexPath);
			
			 IndexReader ireader = DirectoryReader.open(directory);
				total = ireader.maxDoc();
			
//				Set<String> set = new HashSet();
//				set.add("count");
				 
				 for (int i = start; i < total&&i<(start+size); i++) {
						Map<String, Object> map = new HashMap<String, Object>();
						int idoc=reverse?(total-(i+1)):i;
						
						Document doc = ireader.document(idoc );

						 List<IndexableField> fields = doc.getFields();
						 fields.forEach(e->{
							 IndexableField indexablefield=e;
							 map.put(indexablefield.name(),  indexablefield.stringValue());
							
							
						 });
//						 _print(map);
						 list.add(map);
						
					}
				 
				 	
			 ireader.close(); 
		 } catch (IOException    e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		 return new Page(start, size, total,list);
	}
	
	
	
	/**
	 * 
	* @Title: get
	* @Description: 取得数据
	* @param @param tableName
	* @param @param start
	* @param @param size
	* @param @param fields
	* @param @param sortField
	* @param @return    设定文件
	* @return Page    返回类型
	* @throws
	 */
	public Page get(int start,int size,Field[] fields,SortField[] sortField,String ... tableNames) {
		
		
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		int total=0;

		try {
			
			
			 IndexSearcher isearcher =_getSearcher(tableNames);
			 
			
			
			 MultiPhraseQuery query = new MultiPhraseQuery() ;
			 Term[] terms= new Term[fields.length];
			 for (int i=0;i<fields.length;i++) {
				 terms[i] = new Term(fields[i].getName(),fields[i].getValue());
			}
			query.add(terms);
			TopDocs topDocs=null;
			if(sortField==null)  //排序字段为空 ，也就Top排序
			{
				topDocs=isearcher.search(query, CONFIG.getSize());
			}else
			{
				topDocs=isearcher.search(query, CONFIG.getSize(), new Sort(sortField));
			}
			 ScoreDoc[] docs = topDocs.scoreDocs;
		   total =docs.length;
			 
			for (int i = start; i < docs.length&&i<(start+size); i++) {
				 
				Map<String, Object> map = new HashMap<String, Object>();
				Document doc = isearcher.doc(docs[i].doc);
				 List<IndexableField> indexfields = doc.getFields();
				 indexfields.forEach(e->{
					 IndexableField indexablefield=e;
					 map.put(indexablefield.name(),  indexablefield.stringValue());
					
					 
				 });
//				 _print(map);
				 list.add(map);
			 }
			 
//			 ireader.close(); 
		 } catch (IOException    e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
		
		return new Page(start, size, total, list);
		
	}
	
	
	/**
	 * 
	* @Title: get
	* @Description: 取得数据
	* @param @param tableName
	* @param @param start
	* @param @param size
	* @param @param fields
	* @param @param flags
	* @param @param sortField
	* @param @return    设定文件
	* @return Page    返回类型
	* @throws
	* 
	*  String[] fields = {"filename", "contents", "description"};
 			BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD,
                BooleanClause.Occur.MUST,
                BooleanClause.Occur.MUST_NOT};
            (filename:query) +(contents:query) -(description:query)     
            
            SHOULD:分词搜索
            MUST:必须
            MUST_NOT: 必须没有  
	 */
	public Page get(int start,int size,Field[] fields,BooleanClause.Occur[] flags,SortField[] sortField,String ... tableNames) {
		
		
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		int total=0;

		try {
			
			
			 IndexSearcher isearcher = _getSearcher(tableNames);
			 
			String[] queries = new String[fields.length];
			String[] sfield   = new String[fields.length];
			for (int i = 0; i < fields.length; i++) {
				queries[i]=fields[i].getValue();
				sfield[i]=fields[i].getName();
			}
			Query query = MultiFieldQueryParser.parse(queries, sfield, flags, analyzer);
			
			TopDocs topDocs=null;
			if(sortField==null)  //排序字段为空 ，也就Top排序
			{
				topDocs=isearcher.search(query, CONFIG.getSize());
			}else
			{
				topDocs=isearcher.search(query, CONFIG.getSize(), new Sort(sortField));
			}
			ScoreDoc[] docs = topDocs.scoreDocs;
		   total =docs.length;
			 
			for (int i = start; i < docs.length&&i<(start+size); i++) {
				 
				Map<String, Object> map = new HashMap<String, Object>();
				Document doc = isearcher.doc(docs[i].doc);
				
				 List<IndexableField> indexfields = doc.getFields();
				 indexfields.forEach(e->{
					 IndexableField indexablefield=e;
					
					 map.put(indexablefield.name(),  indexablefield.stringValue());
					
					 
				 });
//				 _print(map);
				 list.add(map);
			 }
			 
//			 ireader.close(); 
		 } catch (IOException | ParseException    e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
		
		return new Page(start, size, total, list);
		
	}
	
	
	
	/**
	 * 
	* @Title: get
	* @Description: 取得数据
	* @param @param tableName
	* @param @param start
	* @param @param size
	* @param @param fields
	* @param @param querie
	* @param @param flags
	* @param @param sortField
	* @param @return    设定文件
	* @return Page    返回类型
	* @throws
	 */
	public Page get(int start,int size,String[] fields,String querie,BooleanClause.Occur[] flags,SortField[] sortField,String ... tableNames) {
		
		
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		int total=0;
	
		try {
			 
			
			 IndexSearcher isearcher = _getSearcher(tableNames);
			 
		
			
			Query query = MultiFieldQueryParser.parse(querie, fields, flags, analyzer);
			
			TopDocs topDocs=null;
			if(sortField==null)  //排序字段为空 ，也就Top排序
			{
				topDocs=isearcher.search(query, CONFIG.getSize());
			}else
			{
				topDocs=isearcher.search(query, CONFIG.getSize(), new Sort(sortField));
			}
			
			 ScoreDoc[] docs = topDocs.scoreDocs;
		   total =docs.length;
			 
			for (int i = start; i < docs.length&&i<(start+size); i++) {
				 
				Map<String, Object> map = new HashMap<String, Object>();
				Document doc = isearcher.doc(docs[i].doc);
				 List<IndexableField> indexfields = doc.getFields();
				 indexfields.forEach(e->{
					 IndexableField indexablefield=e;
					 map.put(indexablefield.name(),  indexablefield.stringValue());
					
					 
				 });
//				 _print(map);
				 list.add(map);
			 }
			 
//			 ireader.close(); 
		 } catch (IOException | ParseException    e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
		
		return new Page(start, size, total, list);
		
	}
	
	
	
	
	public static void main(String[] args) {
//		LuceneManage.getInstance().createTable(true,"news");
		List<Field> list= new ArrayList<Field>();
		list.add(new Field("id", "1", Field.Type.Key));
		list.add(new Field("class", "10", Field.Type.String));
		list.add(new Field("count", "10", Field.Type.String));
		list.add(new Field("name", "央视新闻说“感染埃博拉会变僵尸” ﻿j2me、美国NASA发布“地球将陷入黑暗6天”、专家称“一氧化二氢有剧毒”……面对这些耸人听闻的谣言，网友该如何甄别？昨日，北京市网信办、首都互", Field.Type.Text));


		LuceneManage.getInstance().add( list,"tngou");
//		Field field = new Field("newsclass", "1", Field.Type.String);
//		SortField[] sortField = {new SortField("id",Type.LONG , false)};
//	
//		Field[] fields = new Field[3];
//		fields[0]=field;
//		fields[1]=new Field("title", "天狗", Field.Type.String);
//		fields[2]=new Field("message", "天狗", Field.Type.String);
//		Occur[] flags={BooleanClause.Occur.MUST,BooleanClause.Occur.SHOULD,BooleanClause.Occur.SHOULD};
//		LuceneManage.getInstance().get(1, 10, fields, flags,null, "tngou");
//		
//		String[] sfield={"class","name"};
//		LuceneManage.getInstance().get(0,10,true,"tngou");
//		Field term=new Field("id", "1", Field.Type.Key);
//		Field updates=new Field("count", "1", Field.Type.String);
//		LuceneManage.getInstance().update("news", term, updates);
//		map=LuceneManage.getInstance().getByid("news","11111cccccc");
//		System.err.println(map.get("name"));
		Field field = new Field("id", "1", null);
//		LuceneManage.getInstance().delete(field, "tngou");
	}

	
	
	
	/**
	 * 
	* @Title: _getSearcher
	* @Description: 取得索引信息
	* @param @param tableNames
	* @param @return
	* @param @throws IOException    设定文件
	* @return IndexSearcher    返回类型
	* @throws
	 */
	private IndexSearcher _getSearcher(String ... tableNames) throws IOException {
		if(tableNames==null)
		{
			tableNames=new String[1];
			tableNames[0]=DEFAULT_TABLE;
		}
		IndexReader[] readers = new IndexReader[tableNames.length];
		int idx = 0;
		for (String tableName : tableNames) {
			File indexPath= new File(CONFIG.getPath(), tableName);
			FSDirectory dir = FSDirectory.open(indexPath);
			readers[idx++] = DirectoryReader.open(dir);
		}
		IndexSearcher isearcher = new IndexSearcher(new MultiReader(readers, true));
		return isearcher;
	}

	private void _print(Map<String, Object> map) {
		
		Set<Entry<String, Object>> sets = map.entrySet();
		for (Entry<String, Object> entry : sets) {
			System.err.println(entry.getKey()+":"+entry.getValue());
		}
		
		System.err.println("**************************************");
	}
	
	
}
